package com.yz.fanrenmianshi.controller;

import cn.dev33.satoken.annotation.SaCheckRole;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yz.fanrenmianshi.common.BaseResponse;
import com.yz.fanrenmianshi.common.DeleteRequest;
import com.yz.fanrenmianshi.common.ErrorCode;
import com.yz.fanrenmianshi.common.ResultUtils;
import com.yz.fanrenmianshi.constant.UserConstant;
import com.yz.fanrenmianshi.exception.BusinessException;
import com.yz.fanrenmianshi.exception.ThrowUtils;
import com.yz.fanrenmianshi.manager.CounterManager;
import com.yz.fanrenmianshi.model.dto.questioncomment.*;
import com.yz.fanrenmianshi.model.entity.QuestionComment;
import com.yz.fanrenmianshi.model.entity.User;
import com.yz.fanrenmianshi.model.vo.QuestionCommentVO;
import com.yz.fanrenmianshi.service.CommentThumbRedisService;
import com.yz.fanrenmianshi.service.QuestionCommentService;
import com.yz.fanrenmianshi.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 题目评论接口
 *
 */
@RestController
@RequestMapping("/questionComment")
@Slf4j
public class QuestionCommentController {

    @Resource
    private QuestionCommentService questionCommentService;

    @Resource
    private UserService userService;

    @Resource
    private CommentThumbRedisService commentThumbRedisService;

    @Resource
    private CounterManager counterManager;


    // region 增删改查

    /**
     * 创建题目评论
     *
     * @param questionCommentAddRequest
     * @param request
     * @return
     */
    @PostMapping("/add")
    public BaseResponse<Long> addQuestionComment(@RequestBody QuestionCommentAddRequest questionCommentAddRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(questionCommentAddRequest == null, ErrorCode.PARAMS_ERROR);
        // 将实体类和 DTO 进行转换
        QuestionComment questionComment = new QuestionComment();
        BeanUtils.copyProperties(questionCommentAddRequest, questionComment);
        // 数据校验
        questionCommentService.validQuestionComment(questionComment, true);
        // 填充默认值
        User loginUser = userService.getLoginUser(request);
        questionComment.setUserId(loginUser.getId());

        // 处理评论关系
        Long parentId = questionComment.getParentId();
        if (parentId == null || parentId <= 0) {
            // 如果没有父评论，则为根评论
            questionComment.setParentId(0L);
            questionComment.setRootId(0L);
            questionComment.setReplyUserId(0L);
        } else {
            // 如果有父评论，则查询父评论信息
            QuestionComment parentComment = questionCommentService.getById(parentId);
            ThrowUtils.throwIf(parentComment == null, ErrorCode.NOT_FOUND_ERROR, "父评论不存在");

            // 设置根评论ID
            if (parentComment.getRootId() == 0) {
                // 如果父评论是根评论，则根评论ID为父评论ID
                questionComment.setRootId(parentId);
            } else {
                // 如果父评论不是根评论，则根评论ID与父评论的根评论ID相同
                questionComment.setRootId(parentComment.getRootId());
            }

            // 设置回复用户ID为父评论的创建者ID
            questionComment.setReplyUserId(parentComment.getUserId());
        }

        // 初始化点赞数
        questionComment.setThumbNum(0);

        // 写入数据库
        boolean result = questionCommentService.save(questionComment);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        // 返回新写入的数据 id
        long newQuestionCommentId = questionComment.getId();
        return ResultUtils.success(newQuestionCommentId);
    }

    /**
     * 删除题目评论
     *
     * @param deleteRequest
     * @param request
     * @return
     */
    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteQuestionComment(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User user = userService.getLoginUser(request);
        long id = deleteRequest.getId();
        // 判断是否存在
        QuestionComment oldQuestionComment = questionCommentService.getById(id);
        ThrowUtils.throwIf(oldQuestionComment == null, ErrorCode.NOT_FOUND_ERROR);
        // 仅本人或管理员可删除
        if (!oldQuestionComment.getUserId().equals(user.getId()) && !userService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        // 级联删除评论及其所有子评论
        questionCommentService.cascadeDeleteComment(id);
        return ResultUtils.success(true);
    }


    /**
     * 批量删除题目评论
     * @param questionCommentBatchDeleteRequest
     * @param request
     * @return
     */
    @PostMapping("/delete/batch")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> batchDeleteQuestionComment(@RequestBody QuestionCommentBatchDeleteRequest questionCommentBatchDeleteRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(questionCommentBatchDeleteRequest == null, ErrorCode.PARAMS_ERROR);
        User loginUser = userService.getLoginUser(request);
        ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NOT_LOGIN_ERROR);
        List<Long> questionCommentIdList = questionCommentBatchDeleteRequest.getQuestionCommentIdList();
        questionCommentService.batchDeleteQuestions(questionCommentIdList);
        return ResultUtils.success(true);
    }


    /**
     * 更新题目评论（仅管理员可用）
     *
     * @param questionCommentUpdateRequest
     * @return
     */
    @PostMapping("/update")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> updateQuestionComment(@RequestBody QuestionCommentUpdateRequest questionCommentUpdateRequest) {
        if (questionCommentUpdateRequest == null || questionCommentUpdateRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 将实体类和 DTO 进行转换
        QuestionComment questionComment = new QuestionComment();
        BeanUtils.copyProperties(questionCommentUpdateRequest, questionComment);
        // 数据校验
        questionCommentService.validQuestionComment(questionComment, false);
        // 判断是否存在
        long id = questionCommentUpdateRequest.getId();
        QuestionComment oldQuestionComment = questionCommentService.getById(id);
        ThrowUtils.throwIf(oldQuestionComment == null, ErrorCode.NOT_FOUND_ERROR);
        // 操作数据库
        boolean result = questionCommentService.updateById(questionComment);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(true);
    }

    /**
     * 根据 id 获取题目评论（封装类）
     *
     * @param id
     * @return
     */
    @GetMapping("/get/vo")
    public BaseResponse<QuestionCommentVO> getQuestionCommentVOById(long id, HttpServletRequest request) {
        ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);
        // 查询数据库
        QuestionComment questionComment = questionCommentService.getById(id);
        ThrowUtils.throwIf(questionComment == null, ErrorCode.NOT_FOUND_ERROR);
        // 获取封装类
        return ResultUtils.success(questionCommentService.getQuestionCommentVO(questionComment, request));
    }

    /**
     * 分页获取题目评论列表（仅管理员可用）
     *
     * @param questionCommentQueryRequest
     * @return
     */
    @PostMapping("/list/page")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<QuestionComment>> listQuestionCommentByPage(@RequestBody QuestionCommentQueryRequest questionCommentQueryRequest) {
        long current = questionCommentQueryRequest.getCurrent();
        long size = questionCommentQueryRequest.getPageSize();
        // 查询数据库
        Page<QuestionComment> questionCommentPage = questionCommentService.page(new Page<>(current, size),
                questionCommentService.getQueryWrapper(questionCommentQueryRequest));
        return ResultUtils.success(questionCommentPage);
    }

    /**
     * 分页获取题目评论列表（封装类）
     *
     * @param questionCommentQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/list/page/vo")
    public BaseResponse<Page<QuestionCommentVO>> listQuestionCommentVOByPage(@RequestBody QuestionCommentQueryRequest questionCommentQueryRequest,
                                                                             HttpServletRequest request) {
        ThrowUtils.throwIf(questionCommentQueryRequest == null, ErrorCode.PARAMS_ERROR);

        // 获取分页参数，使用默认值防止空值
        long current = questionCommentQueryRequest.getCurrent();
        long size = questionCommentQueryRequest.getPageSize();

        // 如果current为0或负数，设置默认值
        if (current <= 0) {
            current = 1;
        }

        // 如果size为0或负数，设置默认值
        if (size <= 0) {
            size = 10;
        }

        // 限制爬虫
        ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);

        // 只查询顶级评论（parentId为0或null）
        questionCommentQueryRequest.setParentId(0L);

        // 查询数据库
        Page<QuestionComment> questionCommentPage = questionCommentService.page(new Page<>(current, size),
                questionCommentService.getQueryWrapper(questionCommentQueryRequest));

        // 获取封装类
        Page<QuestionCommentVO> questionCommentVOPage = questionCommentService.getQuestionCommentVOPage(questionCommentPage, request);

        // 为每个顶级评论获取子评论
        List<QuestionCommentVO> topLevelComments = questionCommentVOPage.getRecords();
        if (!topLevelComments.isEmpty()) {
            // 获取所有子评论
            QuestionCommentQueryRequest childQueryRequest = new QuestionCommentQueryRequest();
            childQueryRequest.setQuestionId(questionCommentQueryRequest.getQuestionId());
            QueryWrapper<QuestionComment> childQueryWrapper = questionCommentService.getQueryWrapper(childQueryRequest);
            // 查询parentId不为0的评论（子评论）
            childQueryWrapper.ne("parentId", 0);
            List<QuestionComment> allChildComments = questionCommentService.list(childQueryWrapper);

            // 将子评论转换为VO并按parentId分组
            List<QuestionCommentVO> childCommentVOs = allChildComments.stream()
                    .map(comment -> questionCommentService.getQuestionCommentVO(comment, request))
                    .collect(Collectors.toList());

            Map<Long, List<QuestionCommentVO>> childCommentsMap = childCommentVOs.stream()
                    .collect(Collectors.groupingBy(comment -> comment.getParentId()));

            // 为每个顶级评论设置子评论
            topLevelComments.forEach(topComment -> {
                List<QuestionCommentVO> children = childCommentsMap.get(topComment.getId());
                if (children != null) {
                    topComment.setChildren(children);
                }
            });
        }

        return ResultUtils.success(questionCommentVOPage);
    }

    /**
     * 分页获取当前登录用户创建的题目评论列表
     *
     * @param questionCommentQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/my/list/page/vo")
    public BaseResponse<Page<QuestionCommentVO>> listMyQuestionCommentVOByPage(@RequestBody QuestionCommentQueryRequest questionCommentQueryRequest,
                                                                               HttpServletRequest request) {
        ThrowUtils.throwIf(questionCommentQueryRequest == null, ErrorCode.PARAMS_ERROR);
        // 补充查询条件，只查询当前登录用户的数据
        User loginUser = userService.getLoginUser(request);
        questionCommentQueryRequest.setUserId(loginUser.getId());
        long current = questionCommentQueryRequest.getCurrent();
        long size = questionCommentQueryRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
        // 查询数据库
        Page<QuestionComment> questionCommentPage = questionCommentService.page(new Page<>(current, size),
                questionCommentService.getQueryWrapper(questionCommentQueryRequest));
        // 获取封装类
        return ResultUtils.success(questionCommentService.getQuestionCommentVOPage(questionCommentPage, request));
    }

    /**
     * 编辑题目评论（给用户使用）
     *
     * @param questionCommentEditRequest
     * @param request
     * @return
     */
    @PostMapping("/edit")
    public BaseResponse<Boolean> editQuestionComment(@RequestBody QuestionCommentEditRequest questionCommentEditRequest, HttpServletRequest request) {
        if (questionCommentEditRequest == null || questionCommentEditRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 将实体类和 DTO 进行转换
        QuestionComment questionComment = new QuestionComment();
        BeanUtils.copyProperties(questionCommentEditRequest, questionComment);
        // 数据校验
        questionCommentService.validQuestionComment(questionComment, false);
        User loginUser = userService.getLoginUser(request);
        // 判断是否存在
        long id = questionCommentEditRequest.getId();
        QuestionComment oldQuestionComment = questionCommentService.getById(id);
        ThrowUtils.throwIf(oldQuestionComment == null, ErrorCode.NOT_FOUND_ERROR);
        // 仅本人或管理员可编辑
        if (!oldQuestionComment.getUserId().equals(loginUser.getId()) && !userService.isAdmin(loginUser)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        // 操作数据库
        boolean result = questionCommentService.updateById(questionComment);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(true);
    }

    //评论点赞相关接口
    /**
     * 点赞评论
     *
     * @param commentId 评论ID
     * @param request HTTP请求
     * @return 点赞结果
     */
    @PostMapping("/thumb/{commentId}")
    public BaseResponse<Boolean> thumbComment(@PathVariable Long commentId, HttpServletRequest request) {
        ThrowUtils.throwIf(commentId == null || commentId <= 0, ErrorCode.PARAMS_ERROR, "评论ID不能为空");

        // 获取登录用户
        User loginUser = userService.getLoginUser(request);

        // 检查评论是否存在
        QuestionComment comment = questionCommentService.getById(commentId);
        ThrowUtils.throwIf(comment == null, ErrorCode.NOT_FOUND_ERROR, "评论不存在");

        // 管理员不受限流限制，直接执行点赞操作
        if (userService.isAdmin(loginUser)) {
            boolean result = commentThumbRedisService.likeComment(commentId, loginUser.getId());
            return ResultUtils.success(result);
        }

        // 非管理员用户需要进行限流保护：1秒内最多5次点赞
        String rateLimitKey = "thumb:rate:limit:" + loginUser.getId();
        long count = counterManager.incrAndGetCounter(rateLimitKey, 1, TimeUnit.SECONDS);

        if (count > 5) {
            log.warn("用户点赞频率过高 - 用户ID: {}, 评论ID: {}, 1秒内点赞次数: {}", loginUser.getId(), commentId, count);
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "点赞频率过高，请稍后再试");
        }

        // 执行点赞操作
        boolean result = commentThumbRedisService.likeComment(commentId, loginUser.getId());
        return ResultUtils.success(result);
    }

    /**
     * 取消点赞评论
     *
     * @param commentId 评论ID
     * @param request HTTP请求
     * @return 取消点赞结果
     */
    @DeleteMapping("/thumb/{commentId}")
    public BaseResponse<Boolean> unthumbComment(@PathVariable Long commentId, HttpServletRequest request) {
        ThrowUtils.throwIf(commentId == null || commentId <= 0, ErrorCode.PARAMS_ERROR, "评论ID不能为空");

        // 获取登录用户
        User loginUser = userService.getLoginUser(request);

        // 检查评论是否存在
        QuestionComment comment = questionCommentService.getById(commentId);
        ThrowUtils.throwIf(comment == null, ErrorCode.NOT_FOUND_ERROR, "评论不存在");

        // 管理员不受限流限制，直接执行取消点赞操作
        if (userService.isAdmin(loginUser)) {
            boolean result = commentThumbRedisService.unlikeComment(commentId, loginUser.getId());
            return ResultUtils.success(result);
        }

        // 非管理员用户需要进行限流保护：1秒内最多5次取消点赞
        String rateLimitKey = "unthumb:rate:limit:" + loginUser.getId();
        long count = counterManager.incrAndGetCounter(rateLimitKey, 1, TimeUnit.SECONDS);

        if (count > 5) {
            log.warn("用户取消点赞频率过高 - 用户ID: {}, 评论ID: {}, 1秒内取消点赞次数: {}", loginUser.getId(), commentId, count);
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "取消点赞频率过高，请稍后再试");
        }

        // 执行取消点赞操作
        boolean result = commentThumbRedisService.unlikeComment(commentId, loginUser.getId());
        return ResultUtils.success(result);
    }

    /**
     * 检查用户是否点赞了评论
     *
     * @param commentId 评论ID
     * @param request HTTP请求
     * @return 点赞状态
     */
    @GetMapping("/thumb/status/{commentId}")
    public BaseResponse<Boolean> getCommentThumbStatus(@PathVariable Long commentId, HttpServletRequest request) {
        ThrowUtils.throwIf(commentId == null || commentId <= 0, ErrorCode.PARAMS_ERROR, "评论ID不能为空");

        // 获取登录用户
        User loginUser = userService.getLoginUser(request);

        // 检查用户是否点赞
        boolean hasLiked = commentThumbRedisService.hasUserLikedComment(commentId, loginUser.getId());

        return ResultUtils.success(hasLiked);
    }

    /**
     * 获取评论的点赞数量
     *
     * @param commentId 评论ID
     * @return 点赞数量
     */
    @GetMapping("/thumb/count/{commentId}")
    public BaseResponse<Long> getCommentThumbCount(@PathVariable Long commentId) {
        ThrowUtils.throwIf(commentId == null || commentId <= 0, ErrorCode.PARAMS_ERROR, "评论ID不能为空");

        // 获取点赞数量
        Long thumbCount = commentThumbRedisService.getCommentLikeCount(commentId);

        return ResultUtils.success(thumbCount);
    }

    /**
     * 重新初始化评论点赞数量（临时接口，用于修复数据类型问题）
     *
     * @param commentId 评论ID
     * @return 初始化结果
     */
    @PostMapping("/thumb/reinitialize/{commentId}")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> reinitializeCommentThumbCount(@PathVariable Long commentId) {
        ThrowUtils.throwIf(commentId == null || commentId <= 0, ErrorCode.PARAMS_ERROR, "评论ID不能为空");

        // 重新初始化点赞数量
        commentThumbRedisService.reinitializeCommentLikeCount(commentId);

        return ResultUtils.success(true);
    }

}
